if (String.prototype.startsWith === undefined) {
	String.prototype.startsWith = function(s) {
		if (s==null || s.length > this.length) return false;
		return this.substr(0, s.length) === s;
	};
}

if (String.prototype.endsWith === undefined) {
	String.prototype.endsWith = function(s) {
		if (s==null || s.length > this.length) return false;
		return this.substr(this.length - s.length, s.length) === s;
	};
}

if (Math.uuid === undefined) {
	Math.uuid = function() {//RFC4122, version 4 form
		var s = '0123456789abcdef'.split(''), r = [], i, t;
		r[8] = r[13] = r[18] = r[23] = '-';
		r[14] = '4';
		for (i = 0; i < 36; i++) {
			if (!r[i]) {
				t = 0 | Math.random() * 16;
				r[i] = s[(i == 19) ? (t & 0x03) | 0x08 : t];
			}
		}
		return r.join('');
	};
}
/** framework **/
var sfw = {
	_empty: function() {},
	Http: (function() {
		var _headers = {};

		function _req(method, url, async, callback, query, data) {
			callback = callback || sfw._empty;
			var parameters = {
				type: method,
				async: async,
				cache: false,
				dataType: 'json',
				headers: _headers,
				error: function(r, t, e) {
					callback(r);
				},
				success: function(d, t, r) {
					callback(r, d);
				}
			};
			//parameters.url = (query || false) ? url + '?' + $.param(query) : url;
			if(query || false){

				var t  = '';
				for(var key in query){
					if(t == ''){
						t += (key + '=' + query[key]);
					} else {
						t += ('&' + key + '=' + query[key]);
					}
				}
				parameters.url = url + '?' + t;
			} else {
				parameters.url = url;
			}
			if (data || false) {
				parameters.data = JSON.stringify(data);
				parameters.contentType = 'application/json';
			}
			return $.ajax(parameters);
		}

		return {
			setHeader: function(name, value) {
				_headers[name] = value;
			},
			get: function(url, callback, query) {
				return _req('get', url, true, callback, query, false);
			},
			syncGet: function(url, callback, query) {
				return _req('get', url, false, callback, query, false);
			},
			post: function(url, callback, data, query) {
				return _req('post', url, true, callback, query, data);
			},
			syncPost: function(url, callback, data, query) {
				return _req('post', url, false, callback, query, data);
			},
			put: function(url, callback, data, query) {
				return _req('put', url, true, callback, query, data);
			},
			syncPut: function(url, callback, data, query) {
				return _req('put', url, false, callback, query, data);
			},
			del: function(url, callback) {
				return _req('delete', url, true, callback, false, false);
			},
			syncDel: function(url, callback) {
				return _req('delete', url, false, callback, false, false);
			},
			batch: function(r, s, f) {/** r = [{url:'', method:'', query:{}, data:{}}, ...], s = success callback, f = failure callback **/
				r = r || [];
				var i, l = r.length, syntax = "";
				if (l > 0) {
					for (i = 0; i < l; i++) {
						if (syntax != "") syntax += ",";
						syntax += "$.ajax({dataType:'json',headers:" + JSON.stringify(_headers) + ",url:'";
						syntax += ((r[i].query) ? r[i].url + "?" + $.param(r[i].query) : r[i].url) + "'";
						if (r[i].method) syntax += ",type:'" + r[i].method + "'";
						if (r[i].data) {
							syntax += ",contentType:'application/json'";
							syntax += ",data:'" + JSON.stringify(r[i].data).replace(new RegExp("'","gim"),"\\'").replace(new RegExp("\"","gim"),"\\\"") + "'";
						}
						syntax += "})";
					}
					(new Function("s", "f", "$.when(" + syntax + ").then(s, f);"))(s || sfw._empty, f || sfw._empty);
				}
			},
			handleError: function(xhr, data, filter) {
				if(xhr.getResponseHeader('Connection') == 'close' ){
					document.URL=location.href;
					return true;
				}
				if (Math.floor(xhr.status / 100) != 2) return xhr.statusText;
				if ($.isFunction(filter)) return filter(data);
				return false;
			}
		};
	})(),
	Socket: function(schema, host, port, path) {
		var _ws = false, _listeners = [], _url = schema + "://" + host;
		
		if (port && port.trim().length > 0) url += ":" + port;
		if (path && path.trim().length > 0) {
			if (path.startsWith("/")) url += path;
			else url += "/" + path;
		} else url += "/";
		
		this.self = sfw.Socket;
		
		this.self.prototype.open = function() {
			if (!_ws) {
				_ws = window.WebSocket ? new WebSocket(_url) : {send: sfw._empty, close: sfw._empty};
				_ws.onopen = function(e) {$.each(_listeners, function(i, l) {l.onopen(e);});};
				_ws.onmessage = function(e) {$.each(_listeners, function(i, l) {l.onmessage(e);});};
				_ws.onerror = function(e) {$.each(_listeners, function(i, l) {l.onerror(e);});};
				_ws.onclose = function(e) {$.each(_listeners, function(i, l) {l.onclose(e);});};
			}
		};
		
		this.self.prototype.close = function() {
			if (_ws) {
				_ws.close();
				_ws = false;
			}
		};
		
		this.self.prototype.send = function(message) {
			if (_ws)
				_ws.send(message);
		};
		
		this.self.prototype.addListener = function(listener) {
			listener.onopen = listener.onopen || sfw._empty;
			listener.onmessage = listener.onmessage || sfw._empty;
			listener.onerror = listener.onerror || sfw._empty;
			listener.onclose = listener.onclose || sfw._empty;
			_listeners.push(listener);
		};
		
		this.self.prototype.removeListener = function(listener) {
			var i = $.inArray(listener, _listeners);
			if (i >= 0) delete _listeners[i];
		};
	},
	Cookie: function(domain, path) {
		var _domain = domain, _path = path;
		
		this.self = sfw.Cookie;
		
		this.self.prototype.set = function(key, value, days, secure) {
			var s = key + '=' + escape(value);
			if (days) {
				var date = new Date();
				date.setDate(date.getDate() + days);
				s += '; expires=' + date.toGMTString();
			}
			if (_domain) s += '; domain=' + _domain;
			if (_path) s += '; path=' + _path;
			if (secure) s += '; secure'
			document.cookie = s;
		};
		
		this.self.prototype.get = function(key) {
			var end, start = document.cookie.indexOf(key + '=');
			if (start != -1) {
				start += key.length + 1;
				end = document.cookie.indexOf(';', start);
				if (end == -1) end = document.cookie.length;
				return unescape(document.cookie.substring(start, end));
			}
			return false;
		};
		
		this.self.prototype.remove = function(key) {
			var v = this.get(key);
			if (v) this.set(key, v, -1);
		};
	},
	Language: (function() {
		var _lang, _res = false;
		/* e.g.	
			lang='cn':		_res = {'Hello!': '哈喽！', ...};
			lang='it':		_res = {'Hello!': 'Ciao!', ...};
		*/
		
		function _loaded(xhr, data) {
			var err = Http.handleError(xhr, data, function(d) {
				return d ? false : 'Can not load language package.';
			});
			if (err == false) _res = data;
			else alert(err);
		}
		
		return {
			load: function(lang, url) {
				lang = lang || 'en';
				if (lang != _lang) {
					_lang = lang;
					if (_lang != 'en') Http.syncGet((url || '/lang/') + _lang, _loaded);
					else _res = false;
				}
			},
			getText: function(source) {
				if (_res) {
					var r  = _res[source];
					if (r) return r;
				}
				return source;
			}
		};
	})(),
	Application: (function() {
		var _entrance = [], _exit = [];
		return {
			addEnterListener: function(l) {
				if ($.isFunction(l)) _entrance.push(l);
			},
			addExitListener: function(l) {
				if ($.isFunction(l)) _exit.push(l);
			},
			enter: function() {
				$.each(_entrance, function(i, l) {l();});
			},
			exit: function() {
				$.each(_exit, function(i, l) {l();});
			},
			modules: function(a, min) {
				var exd = min ? ".min.js" : ".js";
				
				$.ajaxSetup({async: false});
				for (var i = 0; i < a.length; i++)
					$.getScript(a[i] + exd);
				$.ajaxSetup({async: true});
			},
			Browser: (function() {
				var _userAgent = navigator.userAgent.toLowerCase();
				return {
					msie: /msie/.test(_userAgent),
					firefox: /firefox/.test(_userAgent),
					chrome: /chrome/.test(_userAgent),
					safari: /safari/.test(_userAgent),
					opera: /opera/.test(_userAgent)
				};
			})()
		};
	})()
};

window.onload = sfw.Application.enter;
window.onunload = sfw.Application.exit;
document.oncontextmenu = function (e) {
    if (document.all) window.event.returnValue = false;// for IE
    else e.preventDefault();
}
